#include "VxIrrLib.h"

//------------------------------------------------------------------------------
//! format entry for display
void HighScoreEntry::GetFormatedHighScore( irr::core::stringw& strRetFormatedEntry )
{
	strRetFormatedEntry.Format( "%11d %15d     %s", this->m_iScore, m_iPlayTime, m_strUserName.c_str() );
}

//------------------------------------------------------------------------------
//! initialize and load from xml file
RCODE HighScores::Startup( const char * pConfigXmlFileName )
{
	m_strConfigFile = pConfigXmlFileName;
	Reset(); // initialize all values to default
	// read any values set in the config file
	RCODE rc = ReadConfig();
	if( rc )
	{
		// attempt again but write out defaults then read in
		WriteConfig();
		rc = ReadConfig();
	}
	return rc;
}
//------------------------------------------------------------------------------
//! shutdown
RCODE HighScores::Shutdown( void )
{
	return 0;
}

//------------------------------------------------------------------------------
//! reset settings to default
void HighScores::Reset( void )
{
	m_aoEasyHighScores.clear();
	m_aoMediumHighScores.clear();
	m_aoHardHighScores.clear();
}
//------------------------------------------------------------------------------
//! read settings from file
RCODE HighScores::ReadConfig( void )
{
	// open the config xml file
	TiXmlDocument oDocument( m_strConfigFile.c_str() );
	if( 0 == oDocument.LoadFile()) 
	{
		log_msg( 0, "HighScores: Failed loading config file %s\n", m_strConfigFile.c_str() );
		return -1;
	}
	TiXmlElement * poScoresElement = oDocument.FirstChildElement("scores");
	if( NULL == poScoresElement )
	{
		log_msg( 0, "HighScores: not found\n" );
		return -1;
	}
	ReadLevelScores( poScoresElement, "easy",  m_aoEasyHighScores );
	ReadLevelScores( poScoresElement, "medium",  m_aoMediumHighScores );
	ReadLevelScores( poScoresElement, "hard",  m_aoHardHighScores );
	return 0;
}
//------------------------------------------------------------------------------
//! read level scores from file
RCODE HighScores::ReadLevelScores( TiXmlElement * poScoresElement, const char * pLevelName, irr::core::array<HighScoreEntry>& aoScores )
{
	TiXmlElement * poLevelElement = poScoresElement->FirstChildElement(pLevelName);
	if( NULL == poLevelElement )
	{
		log_msg( 0, "HighScores: level %s not found\n", pLevelName );
		return -1;
	}
	TiXmlElement * poCurElement;
	char as8Buf[ 40 ];
	HighScoreEntry oEntry;
	for( int i = 0; i < 10; i++ )
	{
		sprintf( as8Buf, "E%d", i + 1 );
		// Get high score entry
		poCurElement = poLevelElement->FirstChildElement(as8Buf);
		if(poCurElement) 
		{
			poCurElement->QueryIntAttribute("score", &oEntry.m_iScore);
			poCurElement->QueryIntAttribute("time", &oEntry.m_iPlayTime);
			oEntry.m_strUserName = poCurElement->Attribute("name");
			aoScores.push_back( oEntry );
		}
	}
	return 0;
}
//------------------------------------------------------------------------------
//! write settings from file
RCODE HighScores::WriteConfig( void )
{
	TiXmlDocument oDocument;

	// create header
	oDocument.LinkEndChild(new TiXmlDeclaration("1.0", "", ""));
	
	TiXmlElement * poScoresElement = new TiXmlElement("scores");
	poScoresElement->SetAttribute("version", "1.0");
	oDocument.LinkEndChild( poScoresElement );

	// write scores
	WriteLevelScores( poScoresElement, "easy",  m_aoEasyHighScores );
	WriteLevelScores( poScoresElement, "medium",  m_aoMediumHighScores );
	WriteLevelScores( poScoresElement, "hard",  m_aoHardHighScores );
	// Write file
	if( false == oDocument.SaveFile( m_strConfigFile.c_str() ) )
	{
		return -1;
	}
	return 0;
}
//------------------------------------------------------------------------------
//! read level scores from file
RCODE HighScores::WriteLevelScores( TiXmlElement * poScoresElement, const char * pLevelName, irr::core::array<HighScoreEntry>& aoScores )
{
	TiXmlElement * poLevelElement = new TiXmlElement(pLevelName);

	TiXmlElement * poCurElement;
	char as8Buf[ 40 ];
	HighScoreEntry oEntry;
	for( int i = 0; i < aoScores.size(); i++ )
	{
		sprintf( as8Buf, "E%d", i + 1 );
		// Get high score entry
		poCurElement = new TiXmlElement(as8Buf);
		if(poCurElement) 
		{
			poCurElement->SetAttribute("score", aoScores[i].m_iScore);
			poCurElement->SetAttribute("time", aoScores[i].m_iPlayTime);
			poCurElement->SetAttribute("name", aoScores[i].m_strUserName.c_str());
		}
		poLevelElement->LinkEndChild( poCurElement );
	}
	poScoresElement->LinkEndChild( poLevelElement );
	return 0;
}
//------------------------------------------------------------------------------
//! check if score is higher than any existing score
BOOL HighScores::CheckIsHighScore( irr::core::array<HighScoreEntry>& aoScores, int iLevel, int iScore, int iTime )
{
	if( aoScores.size() < 10 )
	{
		return true;
	}
	for( int i = 0; i < aoScores.size(); i++ )
	{
		if( aoScores[i].m_iScore < iScore )
		{
			return true;
		}
	}
	return false;
}
//------------------------------------------------------------------------------
//! return true if is better score than existing score and belongs in top ten scores
BOOL HighScores::IsHighScore( int iLevel, int iScore, int iTime )
{
	switch( iLevel )
	{
	case 1:
		return CheckIsHighScore( m_aoEasyHighScores, iLevel, iScore, iTime );
	case 2:
		return CheckIsHighScore( m_aoMediumHighScores, iLevel, iScore, iTime );
	case 3:
		return CheckIsHighScore( m_aoHardHighScores, iLevel, iScore, iTime );
	}
	return false;
}

//------------------------------------------------------------------------------
//! add new high score
RCODE HighScores::AddHighScore( int iLevel, const char * pName, int iScore, int iTime )
{
	switch( iLevel )
	{
	case 1:
		return DoAddHighScore( m_aoEasyHighScores, iLevel, pName, iScore, iTime );
	case 2:
		return DoAddHighScore( m_aoMediumHighScores, iLevel, pName, iScore,iTime );
	case 3:
		return DoAddHighScore( m_aoHardHighScores, iLevel, pName,  iScore, iTime );
	}
	return 0;
}
//------------------------------------------------------------------------------
//! add new high score
RCODE HighScores::DoAddHighScore( irr::core::array<HighScoreEntry>& aoScores, int iLevel, const char * pName, int iScore, int iTime )
{
	HighScoreEntry oEntry;
	oEntry.m_strUserName = pName;
	oEntry.m_iScore = iScore;
	oEntry.m_iPlayTime = iTime;
	BOOL bInserted = false;
	for( int i = 0; i < aoScores.size(); i++ )
	{
		if( iScore == aoScores[i].m_iScore )
		{
			if( iTime <= aoScores[i].m_iPlayTime )
			{
				// better or equal time.. insert before 
				aoScores.insert( oEntry, i );
				bInserted = true;
				break;
			}
			else
			{
				// insert after
				if( i == ( aoScores.size() -1 ))
				{
					// is at end of list
					aoScores.push_back( oEntry );
				}
				else
				{
					aoScores.insert( oEntry, i );
				}
				bInserted = true;
				break;
			}
		}
		else if( iScore > aoScores[i].m_iScore )
		{
			aoScores.insert( oEntry, i );
			bInserted = true;
			break;
		}
	}
	if( false == bInserted )
	{
		// add to end
		aoScores.push_back( oEntry );
	}
	if( aoScores.size() > 10 )
	{
		// keep list no more than 10
		aoScores.erase( 10 );
	}
	return WriteConfig();
}


